package cn.zyq.demo.service.wx.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.zyq.demo.beans.sys.SysAdmin;
import cn.zyq.demo.beans.wx.WxPayLog;
import cn.zyq.demo.mapper.wx.WxPayLogMapper;

import cn.zyq.demo.beans.user.User;
import cn.zyq.demo.service.wx.WxPayLogService;
import cn.zyq.demo.system.common.BaseService;
import cn.zyq.demo.system.common.PageParam;
import cn.zyq.demo.system.config.weixin.WxConfig;
import cn.zyq.demo.system.config.weixin.WxMaProperties;
import cn.zyq.demo.system.config.weixin.WxMpProperties;
import cn.zyq.demo.system.config.weixin.WxPayProperties;
import cn.zyq.demo.system.enums.WxPayModuleTypeEnum;
import cn.zyq.demo.system.enums.core.ResponseCodeEnum;
import cn.zyq.demo.system.exception.BusinessException;
import cn.zyq.demo.system.utils.IPUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;

/**
 * 微信支付调用流水
 * 2023-04-23 18:46:08
 */

@Slf4j
@Service
public class WxPayLogServiceImpl extends BaseService implements WxPayLogService {
    @Autowired
    private WxPayLogMapper wxPayLogMapper;

    @Override
    public PageInfo<WxPayLog> list(PageParam pageParam, SysAdmin admin) {
        PageHelper.startPage(pageParam.getPage(), pageParam.getPageSize());
        List<WxPayLog> dbList = this.wxPayLogMapper.list(pageParam.getKv());
        return new PageInfo<>(dbList);
    }

    @Override
    public void add(WxPayLog param, SysAdmin admin) {
        this.setCreateBaseData(param, admin);
        this.wxPayLogMapper.insertSelective(param);
    }

    @Override
    public void update(WxPayLog param, SysAdmin admin) {
        Integer id = param.getWxPayLogID();
        this.setUpdateBaseData(param, admin);
        this.wxPayLogMapper.updateByPrimaryKeySelective(param);
    }

    @Override
    public void del(String serviceID, SysAdmin admin) {
        WxPayLog dbInfo = this.detail(serviceID);
        Integer id = dbInfo.getWxPayLogID();
        this.deleteLogic(id, admin, this.wxPayLogMapper);
    }

    @Override
    public WxPayLog detail(String serviceID, SysAdmin admin) {
        return this.detail(serviceID);
    }

    @Override
    public WxPayLog detail(String serviceID) {
        WxPayLog dbInfo = this.getByServiceID(serviceID, WxPayLog.class, this.wxPayLogMapper);
        this.checkLogicExist(dbInfo);
        return dbInfo;
    }

    @Override
    public WxPayLog prepay(Integer userID, BigDecimal amount, WxPayModuleTypeEnum wxPayModuleTypeEnum, Integer eventId, HttpServletRequest request) {
        User user = this.userService.detailByID(userID);
        String openid = user.getWxMaOpenid();
        if (openid == null) {
            log.error("付款订单的预支付会话标识失败：没有获取用户openid");
            throw new BusinessException(ResponseCodeEnum.ERROR, "调起微信预支付信息失败");
        }
        String tradeNo = user.getCode() + "-" + System.currentTimeMillis();
        // 元转成分
        int amountFee = amount.multiply(new BigDecimal(100)).intValue();

        WxPayLog payLog = this.getCreateInstance(WxPayLog.class, user);
        payLog.setUserID(userID);
        payLog.setOpenid(openid);
        payLog.setTraceSn(tradeNo);
        payLog.setModuleType(Integer.valueOf(wxPayModuleTypeEnum.getValue()));
        payLog.setModuleName(wxPayModuleTypeEnum.getKey());
        payLog.setAmountYuan(amount);
        payLog.setAmount(amountFee);
        payLog.setMchid(WxPayProperties.mchId);
        payLog.setAppid(WxMaProperties.appId);
        payLog.setDescription(wxPayModuleTypeEnum.getKey());
        payLog.setSpbillCreateIp(IPUtil.getIPAddress(request));
        payLog.setEventId(eventId);
        WxPayMpOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(tradeNo);
            orderRequest.setOpenid(openid);
            orderRequest.setAttach(wxPayModuleTypeEnum.getValue() + "");
            orderRequest.setBody(wxPayModuleTypeEnum.getKey() + tradeNo);

            orderRequest.setTotalFee(amountFee);
            orderRequest.setSpbillCreateIp(payLog.getSpbillCreateIp());
            log.debug("支付订单名称：" + orderRequest.getBody());
            result = WxConfig.wxPayService(WxMaProperties.appId).createOrder(orderRequest);

        } catch (Exception e) {
            log.error("付款订单的预支付会话标识失败：{}", e.getMessage());
            log.error(e.getMessage(), e);
            throw new BusinessException(ResponseCodeEnum.ERROR, "调起微信预支付会话失败");
        }
        //组装记录
        payLog.setPayReqRespInfo(JSON.toJSONString(result));
        this.wxPayLogMapper.insertSelective(payLog);
        log.info("【请求结束】 预支付请求信息WxPayMpOrderResult:{}", JSONObject.toJSONString(result));
        return payLog;
    }

    @Override
    @Transactional
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
        String xmlResult = null;
        try {
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        } catch (IOException e) {
            log.error("微信付款成功或失败回调失败：{}", "获取回调消息内容错误!");
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayOrderNotifyResult result = null;
        WxPayLog payLog = null;
        try {
            result = WxConfig.wxPayService(WxMaProperties.appId).parseOrderNotifyResult(xmlResult);
        } catch (WxPayException e) {
            log.error("微信付款成功或失败回调失败：{}", "格式化消息内容错误!");
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }
        WxPayLog updateInfo = new WxPayLog();
        updateInfo.setNotifyInfo(JSON.toJSONString(result));
        updateInfo.setChannelOrderNo(result.getTransactionId());
        updateInfo.setNotifyStatus(result.getResultCode());
        updateInfo.setNotifyAmount(result.getTotalFee());
        updateInfo.setNotifyPayerAmount(result.getTotalFee());
        updateInfo.setSuccessTime(LocalDateTimeUtil.parse(result.getTimeEnd(), "yyyyMMddHHmmss"));
        //获取原请求支付订单
        payLog = this.wxPayLogMapper.selectByOutTradeNo(result.getOutTradeNo());
        if (payLog != null) {
            updateInfo.setWxPayLogID(payLog.getWxPayLogID());
            this.wxPayLogMapper.updateByPrimaryKeySelective(updateInfo);
            payLog = this.wxPayLogMapper.selectByPrimaryKey(payLog.getWxPayLogID());
        } else {
            log.info("没有找到原始订单");
            updateInfo.setTraceSn(result.getOutTradeNo());
            this.setBaseData(updateInfo, new User());
            this.wxPayLogMapper.insertSelective(updateInfo);
        }
        if (!result.getResultCode().equals("SUCCESS")){
            log.error("支付订单：{},支付失败", result.getOutTradeNo());
        }
        log.info("处理腾讯支付平台的订单支付：{}", JSONObject.toJSONString(result));
        String attach = result.getAttach();
        if (attach == null) {
            return WxPayNotifyResponse.fail("没有找到支付的模块");
        }
        if (WxPayModuleTypeEnum.RECHARGE.getValue().equals(attach)) {
            //充值回调
            // return this.accountOrderService.payVoteNotify(payLog);
        } else if (WxPayModuleTypeEnum.ACTIVITY_VOTE.getValue().equals(attach)) {
            //活动投票回调
            // return this.activityVoteService.payVoteNotify(payLog);
        } else if (WxPayModuleTypeEnum.ACTIVITY_GIFT.getValue().equals(attach)) {
            //活动刷礼物回调
            // return this.activityGiftOrderService.payOrderNotify(payLog);
        }

        return WxPayNotifyResponse.fail("支付模块类型错误");
    }
}
